﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Framework.Verifications;
using System.Drawing;

namespace Pixysoft.Framework.Reports.Controller
{
    class ToHtmlController
    {
        private static volatile ToHtmlController instance;

        private static object syncRoot = new Object();

        public static ToHtmlController Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            instance = new ToHtmlController();
                        }
                    }
                }
                return instance;
            }
        }


        public string Convert(IReportLayout layout)
        {
            DivTable table = new DivTable();
            table.Width = layout.Width;

            foreach (IReportLayoutRow layoutrow in layout.GetRows())
            {
                DivRow row = new DivRow();

                foreach (IReportLayoutColumn layoutcolumn in layoutrow.GetColumns())
                {
                    IReportComponent component = layout.GetComponents()[layoutcolumn.ComponentCode];

                    DivColumn column = new DivColumn();
                    column.Height = layoutrow.Height;
                    column.Width = layoutcolumn.Width - 5;
                    if (component != null)
                    {
                        column.Content = component.Text;
                        column.Fontsize = component.FontSize;
                    }
                    row.Columns.Add(column);
                }

                table.Rows.Add(row);
            }

            string html = table.ToString();

            return html;
        }

        public string Convert(IReportTable table, int width)
        {
            HtmlTable htmltable = new HtmlTable();

            htmltable.Width = width;

            IReportColumn[] colheaders = GetHeaderColumns(table);

            IReportRow[] rowheaders = GetHeaderRows(table);

            int headerRowSpan = GetDeep(colheaders);

            int headerColSpan = GetDeep(rowheaders);

            InitializeHeaders(htmltable, headerRowSpan, headerColSpan);

            InitializeColumns(htmltable, 0, GetRange(colheaders), headerRowSpan, colheaders);

            InitializeRows(htmltable, headerRowSpan, headerColSpan, GetRange(rowheaders), rowheaders);

            InitializeCells(htmltable, headerRowSpan, table);

            return htmltable.ToString();
        }

        private IReportColumn[] GetHeaderColumns(IReportTable table)
        {
            List<IReportColumn> list = new List<IReportColumn>();

            foreach (IReportColumn column in table.Columns)
            {
                IReportColumn parent = GetHeaderColumn(column);

                if (!list.Contains(parent))
                    list.Add(parent);
            }

            return list.ToArray();
        }

        private IReportColumn GetHeaderColumn(IReportColumn column)
        {
            if (column.Parent == null)
                return column;

            return GetHeaderColumn(column.Parent);
        }

        private IReportRow[] GetHeaderRows(IReportTable table)
        {
            List<IReportRow> list = new List<IReportRow>();

            foreach (IReportRow row in table.Rows)
            {
                IReportRow parent = GetHeaderRow(row);

                if (!list.Contains(parent))
                    list.Add(parent);
            }

            return list.ToArray();
        }

        private IReportRow GetHeaderRow(IReportRow row)
        {
            if (row.Parent == null)
                return row;

            return GetHeaderRow(row.Parent);
        }


        private void InitializeHeaders(HtmlTable htmlTable, int headerRowSpan, int headerColSpan)
        {
            HtmlRow row = new HtmlRow();
            HtmlColumn column = new HtmlColumn();
            row.Columns.Add(column);
            htmlTable.Rows.Add(row);
            column.ColSpan = headerColSpan;
            column.RowSpan = headerRowSpan;
            column.Content = "www.pixysoft.net";
            column.BackgroundColor = SystemColors.Control;
        }

        private void InitializeColumns(HtmlTable htmlTable, int rowIndex, int totalColumnSpan, int totalRowSpan, IReportColumn[] columns)
        {
            if (columns.Length == 0)
                return;

            foreach (IReportColumn column in columns)
            {
                HtmlRow htmlrow = null;

                if (rowIndex < htmlTable.Rows.Count)
                {
                    htmlrow = htmlTable.Rows[rowIndex];
                }
                else
                {
                    htmlrow = new HtmlRow();

                    htmlTable.Rows.Add(htmlrow);
                }

                HtmlColumn htmlcolumn = new HtmlColumn();

                int currentColumnRange = GetRange(column.Children.ToArray());

                int currentColumnDeep = GetDeep(column.Children.ToArray());

                htmlcolumn.ColSpan = currentColumnRange;

                htmlcolumn.RowSpan = totalRowSpan - currentColumnDeep;

                htmlcolumn.Content = column.HeaderName;

                htmlcolumn.BackgroundColor = SystemColors.Control;

                htmlrow.Columns.Add(htmlcolumn);

                InitializeColumns(htmlTable, rowIndex + htmlcolumn.RowSpan, currentColumnRange, currentColumnDeep, column.Children.ToArray());
            }
        }

        private void InitializeRows(HtmlTable htmlTable, int rowIndex, int totalColumnSpan, int totalRowSpan, IReportRow[] rows)
        {
            if (rows.Length == 0)
                return;

            foreach (IReportRow row in rows)
            {
                HtmlRow htmlrow = null;

                if (rowIndex < htmlTable.Rows.Count)
                {
                    htmlrow = htmlTable.Rows[rowIndex];
                }
                else
                {
                    htmlrow = new HtmlRow();

                    htmlTable.Rows.Add(htmlrow);
                }

                HtmlColumn htmlcolumn = new HtmlColumn();

                int currentColumnRange = GetRange(row.Children.ToArray());

                int currentColumnDeep = GetDeep(row.Children.ToArray());

                htmlcolumn.ColSpan = totalColumnSpan - currentColumnDeep;

                htmlcolumn.RowSpan = currentColumnRange;

                htmlcolumn.Content = row.HeaderName;

                htmlcolumn.BackgroundColor = SystemColors.Control;

                if (string.IsNullOrEmpty(row.HeaderName))
                    htmlcolumn.Content = "-";

                htmlrow.Columns.Add(htmlcolumn);

                InitializeRows(htmlTable, rowIndex, currentColumnDeep, currentColumnRange, row.Children.ToArray());

                rowIndex += htmlcolumn.RowSpan;
            }
        }

        private void InitializeCells(HtmlTable htmlTable, int rowIndex, IReportTable table)
        {
            foreach (IReportRow row in table.Rows)
            {
                foreach (IReportCell cell in row.Cells)
                {
                    HtmlRow htmlrow = htmlTable.Rows[rowIndex];

                    HtmlColumn htmlcolumn = new HtmlColumn();
                    htmlcolumn.ColSpan = 1;
                    htmlcolumn.RowSpan = 1;
                    htmlcolumn.Content = cell.Value.ToString();
                    htmlrow.Columns.Add(htmlcolumn);
                }

                rowIndex++;
            }
        }

        private int GetRange(IReportColumn[] children)
        {
            if (children.Length == 0)
                return 1;

            int range = 0;

            foreach (IReportColumn child in children)
            {
                int childrange = GetRange(child.Children.ToArray());

                range += childrange;
            }

            return range;
        }

        private int GetDeep(IReportColumn[] children)
        {
            if (children.Length == 0)
                return 0;

            int maxdeep = 0;

            foreach (IReportColumn child in children)
            {
                int deep = GetDeep(child.Children.ToArray());

                if (deep > maxdeep)
                    maxdeep = deep;
            }

            return 1 + maxdeep;
        }

        private int GetRange(IReportRow[] children)
        {
            if (children.Length == 0)
                return 1;

            int range = 0;

            foreach (IReportRow child in children)
            {
                int childrange = GetRange(child.Children.ToArray());

                range += childrange;
            }

            return range;
        }

        private int GetDeep(IReportRow[] children)
        {
            if (children.Length == 0)
                return 0;

            int maxdeep = 0;

            foreach (IReportRow child in children)
            {
                int deep = GetDeep(child.Children.ToArray());

                if (deep > maxdeep)
                    maxdeep = deep;
            }

            return 1 + maxdeep;
        }

        private int GetRowIndex(IReportColumn column)
        {
            if (column.Parent == null)
                return 0;

            return 1 + GetRowIndex(column.Parent);
        }

        private int GetRowIndex(IReportRow row)
        {
            if (row.Parent == null)
                return 0;

            return 1 + GetRowIndex(row.Parent);
        }

        class DivTable
        {
            int width = 0;
            int height = 0;
            List<DivRow> rows = new List<DivRow>();

            public List<DivRow> Rows
            {
                get { return rows; }
                set { rows = value; }
            }

            public int Width
            {
                get { return width; }
                set { width = value; }
            }
            public int Height
            {
                get { return height; }
                set { height = value; }
            }


            public override string ToString()
            {
                StringBuilder builder = new StringBuilder();

                builder.AppendFormat("<div style='width:{0}px; height:{1}px;'>", width, height).AppendLine();

                foreach (DivRow row in rows)
                {
                    int maxheight = 0;

                    foreach (DivColumn column in row.Columns)
                    {
                        if (column.Height > maxheight)
                            maxheight = column.Height;
                    }

                    builder.AppendFormat("<div style='width:{0}px; height:{1}px;'>", width, maxheight).AppendLine();

                    foreach (DivColumn column in row.Columns)
                    {
                        builder.AppendFormat("<div style='width:{0}px; height:{1}px; font-size:{2}; float: left;'>",
                            column.Width, column.Height, column.Fontsize * 1.5);

                        builder.Append(column.Content);

                        builder.AppendLine("</div>");
                    }

                    builder.AppendLine("</div>");
                }

                builder.AppendLine("</div>");

                return builder.ToString();
            }
        }

        class DivRow
        {
            List<DivColumn> columns = new List<DivColumn>();
            public List<DivColumn> Columns
            {
                get { return columns; }
                set { columns = value; }
            }
        }

        class DivColumn
        {
            int height = -1;
            int width = -1;
            int fontsize = 9;
            string content;

            public string Content
            {
                get { return content; }
                set { content = value; }
            }
            public int Width
            {
                get { return width; }
                set { width = value; }
            }
            public int Height
            {
                get { return height; }
                set { height = value; }
            }
            public int Fontsize
            {
                get { return fontsize; }
                set { fontsize = value; }
            }
        }

        class HtmlTable
        {
            int border = 1;
            int cellspacing = 0;
            int cellpadding = 10;
            int width = 640;

            List<HtmlRow> rows = new List<HtmlRow>();

            public List<HtmlRow> Rows
            {
                get { return rows; }
                set { rows = value; }
            }

            public int Border
            {
                get { return border; }
                set { border = value; }
            }

            public int Cellspacing
            {
                get { return cellspacing; }
                set { cellspacing = value; }
            }

            public int Cellpadding
            {
                get { return cellpadding; }
                set { cellpadding = value; }
            }

            public int Width
            {
                get { return width; }
                set { width = value; }
            }

            public override string ToString()
            {
                StringBuilder builder = new StringBuilder();

                builder.AppendFormat("<table border='{0}' cellspacing='{1}' cellpadding='{2}' style='width:{3}px; text-align:center;'>",
                    border, cellspacing, cellpadding, width).AppendLine();

                foreach (HtmlRow row in rows)
                {
                    builder.AppendLine("<tr style='height:12px;'>");

                    foreach (HtmlColumn column in row.Columns)
                    {
                        builder.Append("<td ");

                        if (column.ColSpan > 1)
                            builder.AppendFormat("colspan='{0}' ", column.ColSpan);

                        if (column.RowSpan > 1)
                            builder.AppendFormat("rowspan='{0}' ", column.RowSpan);

                        builder.Append("style='");

                        if (column.BackgroundColor != Color.White)
                            builder.AppendFormat("background-color:{0}; font-size:12px;", ColorCoder.Instance.ColorToHtml(column.BackgroundColor));

                        if (column.Width > 0)
                            builder.AppendFormat("width:{0}px; ", column.Width);

                        if (column.Height > 0)
                            builder.AppendFormat("height:{0}px; ", column.Height);

                        builder.Append("'>");

                        builder.Append(column.Content);

                        builder.AppendLine("</td>");

                    }

                    builder.AppendLine("</tr>");
                }

                builder.AppendLine("</table>");

                return builder.ToString();
            }
        }

        class HtmlRow
        {
            List<HtmlColumn> columns = new List<HtmlColumn>();

            public List<HtmlColumn> Columns
            {
                get { return columns; }
                set { columns = value; }
            }
        }

        class HtmlColumn
        {
            int colSpan = 1;
            int rowSpan = 1;
            int width = -1;
            int height = -1;
            string content;
            Color backgroundColor = Color.White;

            public int ColSpan
            {
                get { return colSpan; }
                set { colSpan = value; }
            }
            public int RowSpan
            {
                get { return rowSpan; }
                set { rowSpan = value; }
            }
            public string Content
            {
                get { return content; }
                set { content = value; }
            }
            public Color BackgroundColor
            {
                get { return backgroundColor; }
                set { backgroundColor = value; }
            }
            public int Width
            {
                get { return width; }
                set { width = value; }
            }
            public int Height
            {
                get { return height; }
                set { height = value; }
            }


        }
    }
}
